/*
 * spi_conf.c
 *
 *  Created on: 12/mar/2014
 *      Author: Postazione Embedded
 */


#include "spi_conf.h"

void init_SPIx(spi_Device* device){
	uint8_t GPIO_AF = 0;
	uint32_t RCC_SPI_Periph;
	SPI_InitTypeDef SPI_InitStruct;

	//Retrive the AF and the Bus for the selected SPI device
	if(device->SPIx == SPI1){
			GPIO_AF = GPIO_AF_SPI1;
			RCC_SPI_Periph = RCC_APB2Periph_SPI1;
		}else if(device->SPIx == SPI2){
			GPIO_AF = GPIO_AF_SPI2;
			RCC_SPI_Periph = RCC_APB1Periph_SPI2;
		}else if(device->SPIx == SPI3){
			GPIO_AF = GPIO_AF_SPI3;
			RCC_SPI_Periph = RCC_APB1Periph_SPI3;
		}else return;
	InitGPIO(device->SPI_GPIO,  0x1<<device->SCK_Pin_Source | 0x1<<device ->MISO_Pin_Source | 0x1<<device->MOSI_Pin_Source,
			GPIO_Mode_AF, GPIO_PuPd_NOPULL, GPIO_Speed_50MHz);

	// connect SPI1 pins to SPI alternate function
	GPIO_PinAFConfig(device->SPI_GPIO, device->SCK_Pin_Source, GPIO_AF);
	GPIO_PinAFConfig(device->SPI_GPIO, device->MISO_Pin_Source, GPIO_AF);
	GPIO_PinAFConfig(device->SPI_GPIO, device->MOSI_Pin_Source, GPIO_AF);


	// enable clock for used IO pins

	/* configure pins used by SPI1
	 * PA5 = SCK
	 * PA6 = MISO
	 * PA7 = MOSI
	 */

//	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5;
//	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
//	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
//	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
//	GPIO_Init(GPIOA, &GPIO_InitStruct);


	// enable peripheral clock
	if(RCC_SPI_Periph == RCC_APB2Periph_SPI1){
		RCC_APB2PeriphClockCmd(RCC_SPI_Periph, ENABLE);
	}else{
	   RCC_APB1PeriphClockCmd(RCC_SPI_Periph, ENABLE);
	}
	/* configure SPI1 in Mode 0
	 * CPOL = 0 --> clock is low when idle
	 * CPHA = 0 --> data is sampled at the first edge
	 */
    SPI_Cmd(device->SPIx, DISABLE);
	SPI_InitStruct.SPI_Direction = device->SPI_Direction;// SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
	SPI_InitStruct.SPI_Mode = device->SPI_Mode; //SPI_Mode_Master;     // transmit in master mode, NSS pin has to be always high
	SPI_InitStruct.SPI_DataSize = device->SPI_DataSize;// SPI_DataSize_8b; // one packet of data is 8 bits wide
	SPI_InitStruct.SPI_CPOL = device->SPI_CPOL; //SPI_CPOL_Low;        // clock is low when idle
	SPI_InitStruct.SPI_CPHA = device->SPI_CPHA; //SPI_CPHA_1Edge;      // data sampled at first edge
	SPI_InitStruct.SPI_NSS = device->SPI_NSS; //SPI_NSS_Soft; // set the NSS management to internal and pull internal NSS high
	SPI_InitStruct.SPI_BaudRatePrescaler = device->SPI_BaudRatePrescaler;//SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
	SPI_InitStruct.SPI_FirstBit = device->SPI_FirstBit; //SPI_FirstBit_MSB;// data is transmitted MSB first
	SPI_InitStruct.SPI_CRCPolynomial = device ->SPI_CRCPolynomial;
	SPI_Init(device->SPIx, &SPI_InitStruct);
	SPI_CalculateCRC(device->SPIx, DISABLE);


	SPI_Cmd(device->SPIx, ENABLE); // enable SPI1
}



/* This function is used to transmit and receive data
 * with SPI1
 * 			data --> data to be transmitted
 * 			returns received value
 */

void SPIx_write(spi_Device * device, uint8_t data){
	SPIx_read_write(device, data);
}

uint8_t SPIx_read_write(spi_Device* device, uint8_t data){
	device->SPIx->DR = data; // write data to be transmitted to the SPI data register
	while( !(device->SPIx->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete
	while( !(device->SPIx->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete
	while( device->SPIx->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore
	return device->SPIx->DR; // return received data from SPI data register
}
